package com.dlc.shop.coupon.api.util;

import cn.hutool.core.collection.CollectionUtil;
import com.dlc.shop.bean.app.dto.CouponOrderDto;
import com.dlc.shop.bean.app.dto.ProductItemDto;
import com.dlc.shop.bean.app.dto.ShopCartItemDto;
import com.dlc.shop.bean.enums.CouponProdType;
import com.dlc.shop.bean.enums.CouponType;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.util.Arith;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;

/**
 * 协助优惠券进行选择
 *
 * @author LGH
 */
public class ChooseCouponHelper {
    /**
     * 购物项
     */
    private final List<ShopCartItemDto> shopCartItems;
    /**
     * 含有的优惠券列表
     */
    private final List<CouponOrderDto> shopCoupons;

    /**
     * 选中的优惠券id
     */
    private List<Long> couponUserIds;

    /**
     * 用户是否选中优惠券
     */
    private final Integer userChangeCoupon;
    /**
     * 选中的优惠券
     */
    private CouponOrderDto chooseCoupon;

    /**
     * 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
     */
    private double prodCanUseCouponActualTotal;

    /**
     * 优惠金额
     */
    private double couponReduce;

    /**
     * 优惠金额参与的商品数量
     */
    private Integer reduceNum;

    /**
     * 优惠金额
     */
    private double chooseCouponProdAmount;

    /**
     * 优惠券在订单中的优惠金额
     */
    private double couponInOrderAmount;

    /**
     * 优惠金额关联店铺map
     */
    private final Map<Long, Double> shopReduceMap = new HashMap<>(12);

    public ChooseCouponHelper(List<ShopCartItemDto> shopCartItems, List<CouponOrderDto> shopCoupons, List<Long> couponUserIds, Integer userChangeCoupon) {
        this.shopCartItems = shopCartItems;
        this.shopCoupons = shopCoupons;
        this.couponUserIds = couponUserIds;
        this.userChangeCoupon = userChangeCoupon;
    }

    public CouponOrderDto getChooseCoupon() {
        return chooseCoupon;
    }

    public Map<Long, Double> getShopReduceMap() {
        return shopReduceMap;
    }

    public double getCouponReduce() {
        return this.couponReduce;
    }

    public ChooseCouponHelper invoke() {
        // 没有平台优惠券直接返回
        if (CollectionUtils.isEmpty(shopCartItems)) {
            return this;
        }

        // 用户选中的关于该店铺的优惠券，一家店只能选择一张优惠券
        chooseCoupon = null;
        reduceNum = 0;

        if (Objects.isNull(couponUserIds)) {
            couponUserIds = new ArrayList<>();
        }

        // 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
        prodCanUseCouponActualTotal = 0.0;
        // 处理套餐优惠券消息
        CouponOrderDto firstAvailableCoupon = handleShopCoupons();
        // 没选择优惠券，默认选择第一张可用的优惠券
        if (chooseCoupon == null
                && firstAvailableCoupon != null
                && !Objects.equals(userChangeCoupon, 1)) {
            chooseCoupon = firstAvailableCoupon;
            chooseCouponProdAmount = prodCanUseCouponActualTotal;
        }
        for (CouponOrderDto shopCoupon : shopCoupons) {
            // 该优惠券关联的商品id
            List<Long> prodIds = shopCoupon.getProdIds();
            if (Objects.nonNull(chooseCoupon) && !Objects.equals(shopCoupon.getCouponUserId(), chooseCoupon.getCouponUserId())) {
                continue;
            }
            for (ShopCartItemDto shopCartItem : shopCartItems) {
                if (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) {
                    continue;
                }
                shopCartItem.setIsShareReduce(0);
                // 该商品是否在该优惠券可用
                boolean isCouponsProd = isCouponsProd(shopCartItem.getProdId(), prodIds, shopCoupon.getSuitableProdType());
                if (isCouponsProd) {
                    shopCartItem.setIsShareReduce(1);
                    reduceNum++;
                }
            }
        }
        prodCanUseCouponActualTotal = chooseCouponProdAmount;
        if (chooseCoupon != null) {
            chooseCoupon.setChoose(true);
            couponReduce = chooseCoupon.getReduceAmount();
            couponInOrderAmount = chooseCoupon.getReduceAmount();
            // 设置分摊优惠金额
            this.setShareReduce();
        }
        return this;
    }

    private CouponOrderDto handleShopCoupons() {
        Date now = new Date();
        for (CouponOrderDto shopCoupon : shopCoupons) {
            if (shopCoupon.getStartTime().getTime() > now.getTime() || shopCoupon.getEndTime().getTime() < now.getTime()) {
                continue;
            }
            // 该优惠券关联的商品id
            List<Long> prodIds = shopCoupon.getProdIds();
            // 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            prodCanUseCouponActualTotal = 0.0;
            for (ShopCartItemDto shopCartItem : shopCartItems) {
                // 套餐不参与优惠券活动
                if (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) {
                    continue;
                }
                shopCartItem.setIsShareReduce(0);
                // 该商品是否在该优惠券可用
                boolean isCouponsProd = isCouponsProd(shopCartItem.getProdId(), prodIds, shopCoupon.getSuitableProdType());
                if (isCouponsProd) {
                    shopCartItem.setIsShareReduce(1);
                    prodCanUseCouponActualTotal = Arith.add(prodCanUseCouponActualTotal, shopCartItem.getActualTotal());
                }
            }
            Date date = new Date();
            // 如果该商品实际总金额大于等于优惠券最低使用金额，并且开始时间大于优惠券的使用时间，则优惠券可用
            if (prodCanUseCouponActualTotal >= shopCoupon.getCashCondition() && shopCoupon.getStartTime().getTime() < date.getTime()) {
                // 将优惠券标记为可用状态
                shopCoupon.setCanUse(true);
                if (Objects.nonNull(chooseCoupon)) {
                    continue;
                }
                // 折扣券的优惠金额要根据订单金额实时计算
                if (CouponType.C2D.value().equals(shopCoupon.getCouponType())) {
                    double reduceMoney = Arith.roundByBanker(Arith.sub(prodCanUseCouponActualTotal, Arith.div(Arith.mul(prodCanUseCouponActualTotal,
                            shopCoupon.getCouponDiscount()), 10)), 2);
                    shopCoupon.setReduceAmount(reduceMoney);
                }
                // 聚合 用户选中的关于该店铺的优惠券
                if (couponUserIds.contains(shopCoupon.getCouponUserId())) {
                    chooseCoupon = shopCoupon;
                    chooseCouponProdAmount = prodCanUseCouponActualTotal;
                }
            }
        }
        // 优惠券排序（按可用，折扣金额降序）
        CouponOrderDto firstAvailableCoupon = null;
        if (!CollectionUtil.isEmpty(shopCoupons)) {
            shopCoupons.sort((o1, o2) -> {
                if (o2.isCanUse() == o1.isCanUse()) {
                    return o2.getReduceAmount().compareTo(o1.getReduceAmount());
                }
                return o2.isCanUse() ? 1 : -1;
            });
            // 返回第一张可用优惠券（也是优惠力度最高）
            firstAvailableCoupon = shopCoupons.get(0).isCanUse() ? shopCoupons.get(0) : null;
        }
        return firstAvailableCoupon;
    }

    /**
     * 判断某个商品是否在此优惠券中
     *
     * @param prodId         在该店铺中的商品商品id
     * @param couponProdIds  优惠券关联的商品id
     * @param couponProdType 优惠券适用商品类型
     * @return 商品是否在此优惠券中
     */
    private boolean isCouponsProd(Long prodId, List<Long> couponProdIds, Integer couponProdType) {
        if (CouponProdType.ALL.value().equals(couponProdType)) {
            return true;
        }

        if (CouponProdType.PROD_IN.value().equals(couponProdType)) {
            if (CollectionUtil.isEmpty(couponProdIds)) {
                return false;
            }
            for (Long couponProdId : couponProdIds) {
                if (Objects.equals(couponProdId, prodId)) {
                    return true;
                }
            }
            return false;
        }

        if (CouponProdType.PROD_NO_IN.value().equals(couponProdType)) {
            if (CollectionUtil.isEmpty(couponProdIds)) {
                return true;
            }
            for (Long couponProdId : couponProdIds) {
                if (Objects.equals(couponProdId, prodId)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }



    /**
     * 设置分摊优惠金额
     */

    private void setShareReduce() {
        double sumReduce = 0.0;
        shopCartItems.sort(Comparator.comparing(ProductItemDto::getActualTotal));
        int count = 0;
        // 初步计算优惠券金额
        for (ShopCartItemDto shopCartItem : shopCartItems) {
            // 设置默认值
            shopCartItem.setPlatformShareReduce(null == shopCartItem.getPlatformShareReduce() ? 0L : shopCartItem.getPlatformShareReduce());
            // 套餐商品不参与优惠券，或者优惠金额不分摊
            boolean notShareReduce = (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) || shopCartItem.getIsShareReduce() != 1;
            if (notShareReduce) {
                continue;
            }
            // 分摊金额计算
            // 步骤一： 计算优惠分摊的比例 = 优惠券的总优惠金额） / 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            // 步骤二： 计算商品的优惠券分摊金额 = 分摊比例 * 商品实际金额
            // 实际计算： 优惠券分摊金额 = (商品实际金额 * 优惠券的总优惠金额） / 可用优惠券的商品实际金额（商品实际金额 - 商品分摊金额）
            double shareReduce = Arith.div(Arith.mul(shopCartItem.getActualTotal(), couponInOrderAmount),prodCanUseCouponActualTotal, 2);

            //如果是最后一项可以参与优惠的商品，直接将剩余的优惠金额赋值给他
            if (++count >= reduceNum) {
                shareReduce = Math.min(Arith.sub(chooseCoupon.getReduceAmount(), sumReduce), shopCartItem.getActualTotal());
            }
            // 实际金额只有0.01就不要参与优惠金额分摊了
            if (shopCartItem.getActualTotal() == 0.01) {
                shareReduce = 0D;
            }

            // 商品实际金额等于优惠券分摊金额，商品实际金额最低为0.01，所以优惠券优惠金额要减去0.01
            if (shareReduce == shopCartItem.getActualTotal()) {
                shareReduce = shareReduce - Constant.MIN_PRODUCT_AMOUNT;
            }
            // 分摊的优惠金额不能大于商品实际金额, 取最小值
            else if (shareReduce > shopCartItem.getActualTotal()) {
                shareReduce = shopCartItem.getActualTotal() - Constant.MIN_PRODUCT_AMOUNT;
            }

            // 写入优惠金额
            if (Objects.equals(chooseCoupon.getShopId(), 0L)) {
                // 平台分摊的每一个购物项优惠金额
                shopCartItem.setPlatformShareReduce(Arith.add(shopCartItem.getPlatformShareReduce(), shareReduce));
                shopCartItem.setPlatformCouponAmount(shareReduce);
            } else {
                // 商家分摊的每一个购物项优惠金额
                shopCartItem.setShareReduce(Arith.add(shopCartItem.getShareReduce(), shareReduce));
                shopCartItem.setShopCouponAmount(shareReduce);
            }
            sumReduce = Arith.add(shareReduce, sumReduce);
            shopCartItem.setActualTotal(Arith.sub(shopCartItem.getActualTotal(), shareReduce));
        }


        shopCartItems.sort(Comparator.comparing(ProductItemDto::getActualTotal).reversed());
        // 如果优惠金额分摊后还有剩余，就再分摊一次
        for (ShopCartItemDto shopCartItem : shopCartItems) {
            // 套餐商品不参与优惠券， 或者优惠券不分滩
            boolean notShareReduce = (Objects.nonNull(shopCartItem.getComboId()) && shopCartItem.getComboId() != 0) || shopCartItem.getIsShareReduce() != 1;
            // 可分摊优惠金额，且优惠金额还有剩余
            if (!notShareReduce && sumReduce < chooseCoupon.getReduceAmount()) {
                sumReduce = this.reassembleAmount(sumReduce, shopCartItem);

            }

            Double actualShareReduce = Objects.equals(chooseCoupon.getShopId(), 0L) ? shopCartItem.getPlatformCouponAmount() : shopCartItem.getShopCouponAmount();
            if (Objects.isNull(actualShareReduce)) {
                actualShareReduce = Constant.ZERO_DOUBLE;
            }
            // 将对应店铺优惠券优惠的金额放入map中
            if (shopReduceMap.containsKey(shopCartItem.getShopId())) {
                double shopReduce = shopReduceMap.get(shopCartItem.getShopId());
                shopReduceMap.put(shopCartItem.getShopId(), Arith.add(shopReduce, actualShareReduce));
            } else {
                shopReduceMap.put(shopCartItem.getShopId(), actualShareReduce);
            }
        }
        // 最终如果使用的优惠金额为0,则表示没有使用任何优惠券
        if(sumReduce < 0.01 && chooseCoupon.getReduceAmount() > 0){
            couponReduce = 0L;
            for (CouponOrderDto shopCoupon : shopCoupons) {
                if(Objects.equals(chooseCoupon.getCouponId(),shopCoupon.getCouponId())){
                    shopCoupon.setChoose(false);
                    shopCoupon.setCanUse(false);
                    chooseCoupon = null;
                    break;
                }
            }
        }
    }

    private double reassembleAmount(double sumReduce, ShopCartItemDto shopCartItem) {
        // 当前分摊的优惠金额小于优惠券优惠金额， 再给各个商品分摊下， 按实际金额从大到小
        double shareReduce = Constant.ZERO_DOUBLE;
        // 如果实际金额 大于 0.01, 就再加一点优惠金额
        if (shopCartItem.getActualTotal() > Constant.MIN_PRODUCT_AMOUNT) {
            double actualShareReduce = Arith.sub(chooseCoupon.getReduceAmount(), sumReduce);
            // 计算还可以分摊的金额 - 商品剩余可用于分摊的金额 和 优惠券剩余的可分摊金额 取最小值
            shareReduce = Math.min(Arith.sub(shopCartItem.getActualTotal(), Constant.MIN_PRODUCT_AMOUNT), actualShareReduce);
        }
        if (shareReduce <= 0) {
            return sumReduce;
        }

        // 写入优惠金额
        if (Objects.equals(chooseCoupon.getShopId(), 0L)) {
            // 平台分摊的每一个购物项优惠金额
            shopCartItem.setPlatformShareReduce(Arith.add(shopCartItem.getPlatformShareReduce(), shareReduce));
            shopCartItem.setPlatformCouponAmount(Arith.add(shopCartItem.getPlatformCouponAmount(), shareReduce));
        } else {
            // 商家分摊的每一个购物项优惠金额
            shopCartItem.setShareReduce(Arith.add(shopCartItem.getShareReduce(), shareReduce));
            shopCartItem.setShopCouponAmount(Arith.add(shopCartItem.getShopCouponAmount(), shareReduce));
        }
        sumReduce = Arith.add(sumReduce, shareReduce);
        shopCartItem.setActualTotal(Arith.sub(shopCartItem.getActualTotal(), shareReduce));
        return sumReduce;
    }
}
